package DataSourceFile

import (
	"encoding/binary"
	"lht-go-plugins/LhtPlugins/IntelIpps"
	"math"
	"os"
	"sync/atomic"
	"time"
)

const (
	FFT_OUT_SIZE = 32768 // 固定缓冲区大小，和你 C++ 完全一致
)

// FileDataSourceSimple 极简版，完全模仿你 C++ 逻辑
type FileDataSourceSimple struct {
	file    *os.File
	running atomic.Bool
	fftChan chan []float32 // 最终发射的频谱（长度 = 当前 FFT 长度）

	// 可动态调整的参数（对应你 C++ 的 m_xxx）
	FftNum     int     // 当前 FFT 长度 1024~32768，必须 2^n
	AverageNum int     // 平均次数
	SignalType bool    // true=复数, false=实数
	RefDB      float32 // 根据 FftNum 自动计算的参考电平

	// 内部状态
	cnt     int
	maxDB   float32
	fftOut  []float32 // 累加缓冲区，固定 32768
	real    []float32
	imag    []float32
	magTmp  []float32 // IPP FFT 输出 magnitude
	dataBuf []int16   // 读取的原始 int16 数据（交错）
}

func NewFileDataSourceSimple(path string) (*FileDataSourceSimple, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}

	src := &FileDataSourceSimple{
		file:       f,
		fftChan:    make(chan []float32, 4),
		FftNum:     16384, // 默认值，可外部修改
		AverageNum: 1,
		SignalType: true, // 默认复数
		fftOut:     make([]float32, FFT_OUT_SIZE),
		real:       make([]float32, 32768),
		imag:       make([]float32, 32768),
		magTmp:     make([]float32, 32768),
		dataBuf:    make([]int16, 32768*2), // 最多读 32768 个复数样点
		maxDB:      -120,
	}

	// 初始计算 ref_db
	src.updateRefDB()

	go src.worker()
	return src, nil
}

func (s *FileDataSourceSimple) GetChannel() <-chan []float32 {
	return s.fftChan
}

func (s *FileDataSourceSimple) Stop() {
	s.running.Store(false)
	if s.file != nil {
		s.file.Close()
	}
	close(s.fftChan)
}

// 外部可以随时修改这三个参数，会自动重置累加器（和你 C++ 一模一样）
func (s *FileDataSourceSimple) SetParams(fftNum, avgNum int, complex bool) {
	if fftNum != s.FftNum || avgNum != s.AverageNum || complex != s.SignalType {
		s.FftNum = fftNum
		s.AverageNum = avgNum
		s.SignalType = complex
		s.updateRefDB()

		// 重置累加状态（和你 C++ 完全一致）
		for i := range s.fftOut {
			s.fftOut[i] = 0
		}
		s.cnt = 0
		s.maxDB = -120
	}
}

func (s *FileDataSourceSimple) updateRefDB() {
	switch s.FftNum {
	case 32768:
		s.RefDB = 179
	case 16384:
		s.RefDB = 173
	case 8192:
		s.RefDB = 167
	case 4096:
		s.RefDB = 161
	case 2048:
		s.RefDB = 155
	case 1024:
		s.RefDB = 149
	default:
		s.RefDB = 173 // 16384 的默认值
	}
}

func (s *FileDataSourceSimple) worker() {
	s.running.Store(true)
	ipp := &IntelIpps.IppImpl{}

	// 确保所有可能用到的 FFT 长度都初始化
	for _, n := range []int{1024, 2048, 4096, 8192, 16384, 32768} {
		_ = ipp.FFTInitFloat(n)
	}

	ticker := time.NewTicker(50 * time.Millisecond) // 约 25fps，和你原来差不多
	defer ticker.Stop()

	for s.running.Load() {
		select {
		case <-ticker.C:
			// 1. 读取一帧原始 int16 数据（最多读 FftNum 个复数样点）
			bytesNeeded := s.FftNum * 4 // 复数时 4 字节，实数时只会用到前半
			tmp := make([]byte, bytesNeeded)
			n, err := s.file.Read(tmp)
			if err != nil || n < bytesNeeded {
				if err == os.ErrClosed || !s.running.Load() {
					return
				}
				// 读完了就循环
				s.file.Seek(0, 0)
				continue
			}

			// 转 int16
			for i := 0; i < s.FftNum*2; i += 2 {
				s.dataBuf[i/2] = int16(binary.LittleEndian.Uint16(tmp[i:]))
			}

			// 2. 填 real/imag（和 C++ 完全一样）
			if s.SignalType { // 复数
				for k := 0; k < s.FftNum; k++ {
					s.real[k] = float32(s.dataBuf[2*k])
					s.imag[k] = float32(s.dataBuf[2*k+1])
				}
			} else { // 实数
				for k := 0; k < s.FftNum; k++ {
					s.real[k] = float32(s.dataBuf[k])
					s.imag[k] = 0
				}
			}

			mag := ipp.FFTFloat(s.real[:s.FftNum], s.imag[:s.FftNum])
			if mag == nil {
				continue
			}
			copy(s.magTmp[:s.FftNum], mag)

			if s.SignalType {
				for k := 0; k < s.FftNum/2; k++ {
					a := 10*log10f(s.magTmp[s.FftNum/2+k]) - s.RefDB
					b := 10*log10f(s.magTmp[k]) - s.RefDB

					if s.maxDB < a {
						s.maxDB = a
					}
					if s.maxDB < b {
						s.maxDB = b
					}

					s.fftOut[k] += a/float32(s.AverageNum) + 10
					s.fftOut[s.FftNum/2+k] += b/float32(s.AverageNum) + 10
				}
			} else {
				for k := 0; k < s.FftNum/2; k++ {
					a := 10*log10f(s.magTmp[s.FftNum/2+k]) - s.RefDB
					if s.maxDB < a {
						s.maxDB = a
					}
					s.fftOut[k] += a/float32(s.AverageNum) + 10
				}
			}

			s.cnt++
			if s.cnt >= s.AverageNum {
				// 发射一帧完整的频谱
				outLen := s.FftNum
				if !s.SignalType {
					outLen /= 2
				}
				frame := make([]float32, outLen)
				copy(frame, s.fftOut[:outLen])

				select {
				case s.fftChan <- frame:
				default:
				}

				// 重置（和你 C++ 完全一致）
				for i := range s.fftOut {
					s.fftOut[i] = 0
				}
				s.cnt = 0
				s.maxDB = -120
			}
		}
	}
}

// 辅助函数，和 C 一样
func log10f(x float32) float32 {
	if x <= 0 {
		return -100
	}
	return float32(math.Log10(float64(x)))
}
